package com.panda.utils;

import com.panda.pojo.*;

import java.util.*;

class ComponentUtils {

    static void handle(Context context, List<String> componentTexts) {


        if (componentTexts.size() > 0) {

            List<Document> documents = new ArrayList<>();

            Map<Document, Context> documentContextMap = new HashMap<>();

            //将文档分割出多个组件定义文段
            componentTexts.forEach(s -> {

                Context dc = new Context(context);

                //提取碎片
                s = FragmentUtils.extract(dc, s);

                for (Document document : DocumentSlicer.splice(s)) {

                    documentContextMap.put(document, dc);

                    documents.add(document);

                }
            });

            //将组件依照依赖次序进行排序
            pow(documents);
            documents.sort((o1, o2) -> o2.getPow() - o1.getPow());

            //解析文档
            for (Document document : documents) {
                parse(documentContextMap.get(document), document);
            }


        }

    }

    //一个组件是一个由其他组件构成的聚合体
    private static void parse(Context context, Document document) {

        String n = document.getName();

        int index = n.lastIndexOf(':');

        String pre = "";

        if (index != -1) {

            //前缀
            pre = n.substring(0, index+1);
            n = n.substring(index + 1);
        }

        if (document.getNamespace() != null) {
            n = document.getNamespace() + "/" + n;
        }

        String s = pre + n;

        if (document.getRawAttrs() != null) {
            s += document.getRawAttrs();
        }

        s += document.getBody();

        Map<String, String> stringStringMap = new HashMap<>();

        //提取字符串
        s = StringUtils.extract(stringStringMap, s);

        s = StringUtils.removeAnnotation(s);

        Context c = new Context(context, s);

        c.setFragments(context.getFragments());

        c.setStringMap(stringStringMap);

        // c.setControllerScopes(new HashSet<>());

        c.setParsingComponent(n);

        ParseUtils.parse(c);

        c.addComponentName(c.getParsingComponent());

        Element cmp = c.getRootElement().getLastSubElement();

        Component component = (Component) cmp;

        component.setName(n.replace("/", "_"));

        //本地字符串,组件自行维护
        component.setLocalStringMap(stringStringMap);

        Document.Files files = document.getFiles();

        //添加文档中的文件依赖
        if (files != null) {

            component.setCss(files.getCss());
            component.setJs(files.getJs());
        }

        //组件在map中的名称
        component.setComponentName(n);

        //元素别名
        if (document.getAs() != null) {
            component.setName(document.getAs());
        }

        //移除父元素
        component.setParent(null);

        component.setContext(null);

        //component.setSubBlocks(cmp.getSubBlocks());

        /*******/
/*

        Scope scope = cmp.getScope();

        component.setScope(scope);

        scope.setElement(component);
*/
/*

        component.setBodyText(cmp.getBodyText());

        component.setAttributes(cmp.getAttributes());

        component.setId(cmp.getId());

        component.setCanMappingScopeParams(((Component) cmp).getCanMappingScopeParams());
*/

//        component.setBufferedText(cmp.getBufferedText());

        Component pubComponent = context.pubComponent(n, component);

        if (pubComponent != null) {
            throw new RuntimeException("已经存在相同名称的组件: " + n + " 可以考虑使用命名空间进行区分");
        }

    }


    private static void pow(List<Document> documents) {

        for (Document document : documents) {
            pow(0, documents, document, document, document.getName());
        }


    }

    private static void pow(int refer, List<Document> documents, Document current, Document target, String lp) {

        //防止循环依赖
        if (current == target && !lp.equals(current.getName())) {
            throw new RuntimeException("依赖循环:\n" + lp + "->" + current.getName());
        }


        //如果参照值比自己的值更大把自己的值更新为这个更大的值并且反向递归
        if (refer > current.getPow()) {

            current.setPow(refer);

            //反向递归自己的引用
            Set<String> deps = current.getDeps();

            if (deps != null) {

                for (String dep : deps) {


                    Document document = get(documents, dep);

                    if (document != null) {
                        pow(refer + 1, documents, document, target, lp + "->" + current.getName());
                    }

                }
            }

        }
    }


    private static Document get(List<Document> documents, String name) {

        for (Document document : documents) {

            if (document.getNamespace() != null) {
                if ((document.getNamespace() + "/" + document.getName()).equals(name)) {
                    return document;
                }
            } else if (document.getName().equals(name)) {
                return document;
            }
        }

        return null;
    }



    /*

        组件占位符

        不确定

     */




}

